package com.zenithmind.library.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.common.result.Result;
import com.zenithmind.common.result.ResultCode;
import com.zenithmind.library.enums.BookStatus;
import com.zenithmind.library.enums.BorrowStatus;
import com.zenithmind.library.mapper.BookCopyMapper;
import com.zenithmind.library.mapper.BookMapper;
import com.zenithmind.library.mapper.BorrowRecordMapper;
import com.zenithmind.library.pojo.domain.Book;
import com.zenithmind.library.pojo.domain.BookCopy;
import com.zenithmind.library.pojo.domain.BorrowRecord;
import com.zenithmind.library.pojo.dto.BorrowBookDTO;
import com.zenithmind.library.pojo.dto.RenewBookDTO;
import com.zenithmind.library.pojo.dto.ReturnBookDTO;
import com.zenithmind.library.pojo.query.BorrowRecordQuery;
import com.zenithmind.library.pojo.vo.BorrowRecordVO;
import com.zenithmind.library.pojo.vo.BorrowStatisticsVO;
import com.zenithmind.library.service.BorrowService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 借阅服务实现类
 * 
 * @author ZenithMind
 * @since 2024-06-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BorrowServiceImpl extends ServiceImpl<BorrowRecordMapper, BorrowRecord> implements BorrowService {

    private final BorrowRecordMapper borrowRecordMapper;
    private final BookMapper bookMapper;
    private final BookCopyMapper bookCopyMapper;
    private final RedissonClient redissonClient;

    @Value("${library.borrow.max-books-per-user:5}")
    private Integer maxBooksPerUser;

    @Value("${library.borrow.default-borrow-days:30}")
    private Integer defaultBorrowDays;

    @Value("${library.borrow.max-borrow-days:90}")
    private Integer maxBorrowDays;

    @Value("${library.borrow.renewal-times:2}")
    private Integer maxRenewalTimes;

    @Value("${library.borrow.overdue-fine-per-day:1.0}")
    private Double overdueFinePerDay;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<BorrowRecordVO> borrowBook(BorrowBookDTO borrowDTO) {
        log.info("借阅图书，数据：{}", borrowDTO);

        String lockKey = "borrow:book:" + borrowDTO.getBookId() + ":" + borrowDTO.getUserId();
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 获取分布式锁，防止并发借阅
            if (!lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                return Result.fail(ResultCode.FAIL.getCode(), "系统繁忙，请稍后重试", null);
            }

            // 检查用户是否可以借阅
            Result<Boolean> canBorrowResult = canUserBorrow(borrowDTO.getUserId(), borrowDTO.getBookId());
            if (!canBorrowResult.isSuccess()) {
                return Result.fail(canBorrowResult.getCode(), canBorrowResult.getMsg(), null);
            }

            // 检查图书是否可以借阅
            Result<Boolean> canBookBeBorrowedResult = canBookBeBorrowed(borrowDTO.getBookId());
            if (!canBookBeBorrowedResult.isSuccess()) {
                return Result.fail(canBookBeBorrowedResult.getCode(), canBookBeBorrowedResult.getMsg(), null);
            }

            // 查找可用的图书副本
            BookCopy availableCopy = findAvailableBookCopy(borrowDTO.getBookId(), borrowDTO.getBookCopyId());
            if (availableCopy == null) {
                return Result.fail(ResultCode.NOT_FOUND.getCode(), "没有可借阅的图书副本", null);
            }

            // 创建借阅记录
            BorrowRecord borrowRecord = createBorrowRecord(borrowDTO, availableCopy);
            boolean saved = save(borrowRecord);
            if (!saved) {
                return Result.fail(ResultCode.FAIL.getCode(), "创建借阅记录失败", null);
            }

            // 更新图书副本状态
            updateBookCopyStatus(availableCopy.getId(), BookStatus.BORROWED, borrowDTO.getUserId());

            // 更新图书库存和借阅次数
            updateBookStockAndCount(borrowDTO.getBookId());

            // 转换为VO并返回
            BorrowRecordVO borrowRecordVO = convertToVO(borrowRecord);
            return Result.success(borrowRecordVO);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return Result.fail(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "系统异常，请稍后重试", null);
        } catch (Exception e) {
            log.error("借阅图书失败", e);
            return Result.fail(ResultCode.FAIL.getCode(), "借阅失败：" + e.getMessage(), null);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<BorrowRecordVO> returnBook(ReturnBookDTO returnDTO) {
        log.info("归还图书，数据：{}", returnDTO);

        // 查询借阅记录
        BorrowRecord borrowRecord = getById(returnDTO.getBorrowRecordId());
        if (borrowRecord == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "借阅记录不存在", null);
        }

        // 检查借阅状态
        if (borrowRecord.getStatus() == null || borrowRecord.getStatus() == 1) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "该图书已归还", null);
        }

        // 更新借阅记录
        LocalDate returnDate = returnDTO.getReturnDate() != null ? 
            returnDTO.getReturnDate() : LocalDate.now();
        
        borrowRecord.setReturnDate(returnDate);
        borrowRecord.setStatus(BorrowStatus.RETURNED.getCode());
        borrowRecord.setReturnOperatorId(returnDTO.getOperatorId());
        borrowRecord.setReturnRemarks(returnDTO.getReturnRemarks());
        borrowRecord.setUpdateTime(LocalDateTime.now());

        // 计算逾期天数和罚金
        if (returnDate.isAfter(borrowRecord.getDueDate())) {
            int overdueDays = (int) java.time.temporal.ChronoUnit.DAYS.between(
                borrowRecord.getDueDate(), returnDate);
            double fineAmount = overdueDays * overdueFinePerDay;
            
            borrowRecord.setOverdueDays(overdueDays);
            borrowRecord.setFineAmount(java.math.BigDecimal.valueOf(fineAmount));
        }

        boolean updated = updateById(borrowRecord);
        if (!updated) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新借阅记录失败", null);
        }

        // 更新图书副本状态
        updateBookCopyStatus(borrowRecord.getBookCopyId(), BookStatus.AVAILABLE, null);

        // 更新图书库存
        bookMapper.incrementAvailableCopies(borrowRecord.getBookId());
        bookMapper.decrementBorrowedCopies(borrowRecord.getBookId());

        // 转换为VO并返回
        BorrowRecordVO borrowRecordVO = convertToVO(borrowRecord);
        return Result.success(borrowRecordVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<BorrowRecordVO> renewBook(RenewBookDTO renewDTO) {
        log.info("续借图书，数据：{}", renewDTO);

        // 查询借阅记录
        BorrowRecord borrowRecord = getById(renewDTO.getBorrowRecordId());
        if (borrowRecord == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "借阅记录不存在", null);
        }

        // 检查是否可以续借
        if (!canRenewBook(borrowRecord)) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "该图书不能续借", null);
        }

        // 计算新的到期日期
        LocalDate newDueDate = renewDTO.getNewDueDate();
        if (newDueDate == null) {
            int renewDays = renewDTO.getRenewDays() != null ? 
                renewDTO.getRenewDays() : defaultBorrowDays;
            newDueDate = borrowRecord.getDueDate().plusDays(renewDays);
        }

        // 更新借阅记录
        borrowRecord.setDueDate(newDueDate);
        borrowRecord.setRenewalCount(borrowRecord.getRenewalCount() + 1);
        borrowRecord.setStatus(BorrowStatus.RENEWED.getCode());
        borrowRecord.setUpdateTime(LocalDateTime.now());

        boolean updated = updateById(borrowRecord);
        if (!updated) {
            return Result.fail(ResultCode.FAIL.getCode(), "续借失败", null);
        }

        // 转换为VO并返回
        BorrowRecordVO borrowRecordVO = convertToVO(borrowRecord);
        return Result.success(borrowRecordVO);
    }

    @Override
    public PageResult<BorrowRecordVO> getBorrowRecordPage(BorrowRecordQuery query) {
        log.info("分页查询借阅记录，查询条件：{}", query);

        Page<BorrowRecordVO> page = query.toPage();
        IPage<BorrowRecordVO> result = borrowRecordMapper.selectBorrowRecordPage(page, query);

        return PageResult.of(result.getRecords(), result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public PageResult<BorrowRecordVO> getBorrowRecordsByUser(String userId, BorrowRecordQuery query) {
        log.info("根据用户查询借阅记录，用户ID：{}，查询条件：{}", userId, query);

        Page<BorrowRecordVO> page = query.toPage();
        IPage<BorrowRecordVO> result = borrowRecordMapper.selectBorrowRecordsByUser(page, userId, query);

        return PageResult.of(result.getRecords(), result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public PageResult<BorrowRecordVO> getBorrowRecordsByBook(String bookId, BorrowRecordQuery query) {
        log.info("根据图书查询借阅记录，图书ID：{}，查询条件：{}", bookId, query);

        Page<BorrowRecordVO> page = query.toPage();
        IPage<BorrowRecordVO> result = borrowRecordMapper.selectBorrowRecordsByBook(page, bookId, query);

        return PageResult.of(result.getRecords(), result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public List<BorrowRecordVO> getCurrentBorrowsByUser(String userId) {
        log.info("获取用户当前借阅的图书，用户ID：{}", userId);
        return borrowRecordMapper.selectCurrentBorrowsByUser(userId);
    }

    @Override
    public PageResult<BorrowRecordVO> getOverdueBorrows(BorrowRecordQuery query) {
        log.info("获取逾期借阅记录，查询条件：{}", query);

        Page<BorrowRecordVO> page = query.toPage();
        IPage<BorrowRecordVO> result = borrowRecordMapper.selectOverdueBorrows(page, query);

        return PageResult.of(result.getRecords(), result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public PageResult<BorrowRecordVO> getDueSoonBorrows(Integer days, BorrowRecordQuery query) {
        log.info("获取即将到期的借阅记录，天数：{}，查询条件：{}", days, query);

        Page<BorrowRecordVO> page = query.toPage();
        IPage<BorrowRecordVO> result = borrowRecordMapper.selectDueSoonBorrows(page, days, query);

        return PageResult.of(result.getRecords(), result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public Result<Boolean> canUserBorrow(String userId, String bookId) {
        // 检查用户当前借阅数量
        int currentBorrows = borrowRecordMapper.countUserCurrentBorrows(userId);
        if (currentBorrows >= maxBooksPerUser) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "借阅数量已达上限（" + maxBooksPerUser + "本）", null);
        }

        // 检查用户是否已借阅该图书
        int userBookBorrows = borrowRecordMapper.countUserCurrentBorrowByBook(userId, bookId);
        if (userBookBorrows > 0) {
            return Result.fail(ResultCode.CONFLICT.getCode(), "您已借阅该图书", null);
        }

        // 检查用户是否有逾期记录
        int overdueRecords = borrowRecordMapper.countUserOverdueRecords(userId);
        if (overdueRecords > 0) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "您有逾期未还的图书，请先归还", null);
        }

        // 检查用户是否有未支付的罚金
        Double unpaidFines = borrowRecordMapper.sumUserUnpaidFines(userId);
        if (unpaidFines != null && unpaidFines > 0) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "您有未支付的罚金，请先支付", null);
        }

        return Result.success(true);
    }

    @Override
    public Result<Boolean> canBookBeBorrowed(String bookId) {
        Book book = bookMapper.selectById(bookId);
        if (book == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "图书不存在", null);
        }

        if (book.getStatus() == null || book.getStatus() != 1) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "图书已下架", null);
        }

        if (book.getAvailableCopies() == null || book.getAvailableCopies() <= 0) {
            return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "图书库存不足", null);
        }

        return Result.success(true);
    }

    @Override
    public Result<Double> calculateFine(String borrowRecordId) {
        BorrowRecord borrowRecord = getById(borrowRecordId);
        if (borrowRecord == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "借阅记录不存在", null);
        }

        if (borrowRecord.getReturnDate() != null) {
            return Result.success(borrowRecord.getFineAmount().doubleValue());
        }

        LocalDate dueDate = borrowRecord.getDueDate();
        LocalDate currentDate = LocalDate.now();
        
        if (currentDate.isAfter(dueDate)) {
            int overdueDays = (int) java.time.temporal.ChronoUnit.DAYS.between(dueDate, currentDate);
            double fineAmount = overdueDays * overdueFinePerDay;
            return Result.success(fineAmount);
        }

        return Result.success(0.0);
    }

    @Override
    public Result<Void> payFine(String borrowRecordId, Double amount) {
        // TODO: 实现罚金支付逻辑
        return Result.success();
    }

    @Override
    public Result<Void> sendDueReminder(String borrowRecordId) {
        // TODO: 实现到期提醒逻辑
        return Result.success();
    }

    @Override
    public Result<Integer> batchSendDueReminders(Integer days) {
        // TODO: 实现批量发送到期提醒逻辑
        return Result.success(0);
    }

    @Override
    public BorrowStatisticsVO getBorrowStatistics(LocalDate startDate, LocalDate endDate) {
        return borrowRecordMapper.selectBorrowStatistics(startDate, endDate);
    }

    @Override
    public BorrowStatisticsVO getUserBorrowStatistics(String userId, LocalDate startDate, LocalDate endDate) {
        return borrowRecordMapper.selectUserBorrowStatistics(userId, startDate, endDate);
    }

    @Override
    public BorrowStatisticsVO getBookBorrowStatistics(String bookId, LocalDate startDate, LocalDate endDate) {
        return borrowRecordMapper.selectBookBorrowStatistics(bookId, startDate, endDate);
    }

    @Override
    public Result<String> exportBorrowRecords(BorrowRecordQuery query) {
        // TODO: 实现借阅记录导出逻辑
        return Result.success("/exports/borrow_records_" + System.currentTimeMillis() + ".xlsx");
    }

    @Override
    public Result<Integer> autoProcessOverdueRecords() {
        // TODO: 实现自动处理逾期记录逻辑
        return Result.success(0);
    }

    /**
     * 查找可用的图书副本
     */
    private BookCopy findAvailableBookCopy(String bookId, String bookCopyId) {
        LambdaQueryWrapper<BookCopy> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BookCopy::getBookId, bookId);
        wrapper.eq(BookCopy::getStatus, BookStatus.AVAILABLE.getCode());
        
        if (StringUtils.hasText(bookCopyId)) {
            wrapper.eq(BookCopy::getId, bookCopyId);
        }
        
        wrapper.last("LIMIT 1");
        return bookCopyMapper.selectOne(wrapper);
    }

    /**
     * 创建借阅记录
     */
    private BorrowRecord createBorrowRecord(BorrowBookDTO borrowDTO, BookCopy bookCopy) {
        BorrowRecord borrowRecord = new BorrowRecord();
        borrowRecord.setUserId(borrowDTO.getUserId());
        borrowRecord.setBookCopyId(bookCopy.getId());
        borrowRecord.setBookId(borrowDTO.getBookId());
        borrowRecord.setBorrowDate(LocalDate.now());
        
        LocalDate dueDate = borrowDTO.getDueDate();
        if (dueDate == null) {
            int borrowDays = borrowDTO.getBorrowDays() != null ? 
                borrowDTO.getBorrowDays() : defaultBorrowDays;
            dueDate = LocalDate.now().plusDays(borrowDays);
        }
        borrowRecord.setDueDate(dueDate);
        
        borrowRecord.setStatus(BorrowStatus.BORROWING.getCode());
        borrowRecord.setRenewalCount(0);
        borrowRecord.setMaxRenewalCount(maxRenewalTimes);
        borrowRecord.setBorrowOperatorId(borrowDTO.getOperatorId());
        borrowRecord.setBorrowRemarks(borrowDTO.getBorrowRemarks());
        borrowRecord.setCreateTime(LocalDateTime.now());
        borrowRecord.setUpdateTime(LocalDateTime.now());
        
        return borrowRecord;
    }

    /**
     * 更新图书副本状态
     */
    private void updateBookCopyStatus(String bookCopyId, BookStatus status, String borrowerId) {
        BookCopy bookCopy = new BookCopy();
        bookCopy.setId(bookCopyId);
        bookCopy.setStatus(status.getCode());
        bookCopy.setCurrentBorrowerId(borrowerId);
        bookCopy.setUpdateTime(LocalDateTime.now());
        
        if (status == BookStatus.BORROWED) {
            bookCopy.setLastBorrowDate(LocalDate.now());
            // 增加借阅次数
            BookCopy existingCopy = bookCopyMapper.selectById(bookCopyId);
            if (existingCopy != null) {
                int borrowCount = existingCopy.getBorrowCount() != null ? 
                    existingCopy.getBorrowCount() + 1 : 1;
                bookCopy.setBorrowCount(borrowCount);
            }
        }
        
        bookCopyMapper.updateById(bookCopy);
    }

    /**
     * 更新图书库存和借阅次数
     */
    private void updateBookStockAndCount(String bookId) {
        bookMapper.decrementAvailableCopies(bookId);
        bookMapper.incrementBorrowedCopies(bookId);
        bookMapper.incrementBorrowCount(bookId);
    }

    /**
     * 检查是否可以续借
     */
    private boolean canRenewBook(BorrowRecord borrowRecord) {
        // 检查借阅状态
        if (borrowRecord.getStatus() == null || 
            (borrowRecord.getStatus() != BorrowStatus.BORROWING.getCode() && 
             borrowRecord.getStatus() != BorrowStatus.RENEWED.getCode())) {
            return false;
        }

        // 检查续借次数
        int renewalCount = borrowRecord.getRenewalCount() != null ? borrowRecord.getRenewalCount() : 0;
        int maxRenewal = borrowRecord.getMaxRenewalCount() != null ? 
            borrowRecord.getMaxRenewalCount() : maxRenewalTimes;
        
        if (renewalCount >= maxRenewal) {
            return false;
        }

        // 检查是否逾期
        return !LocalDate.now().isAfter(borrowRecord.getDueDate());
    }

    /**
     * 转换为VO对象
     */
    private BorrowRecordVO convertToVO(BorrowRecord borrowRecord) {
        // TODO: 实现完整的转换逻辑，包括关联数据
        BorrowRecordVO vo = new BorrowRecordVO();
        vo.setId(borrowRecord.getId());
        vo.setUserId(borrowRecord.getUserId());
        vo.setBookCopyId(borrowRecord.getBookCopyId());
        vo.setBookId(borrowRecord.getBookId());
        vo.setBorrowDate(borrowRecord.getBorrowDate());
        vo.setDueDate(borrowRecord.getDueDate());
        vo.setReturnDate(borrowRecord.getReturnDate());
        vo.setStatus(borrowRecord.getStatus());
        vo.setRenewalCount(borrowRecord.getRenewalCount());
        vo.setMaxRenewalCount(borrowRecord.getMaxRenewalCount());
        vo.setOverdueDays(borrowRecord.getOverdueDays());
        vo.setFineAmount(borrowRecord.getFineAmount());
        vo.setFinePaid(borrowRecord.getFinePaid());
        vo.setBorrowRemarks(borrowRecord.getBorrowRemarks());
        vo.setReturnRemarks(borrowRecord.getReturnRemarks());
        vo.setCreateTime(borrowRecord.getCreateTime());
        vo.setUpdateTime(borrowRecord.getUpdateTime());
        return vo;
    }
}
